package cn.pugle.base.net.socket;

import cn.pugle.base.net.socket.client.CONS;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 测试异步handler
 *
 * @author tzp
 */
public class AioFutureServer1 {
    public static HashMap<AsynchronousSocketChannel, ByteBuffer> readBufferMap;

    public static void main(String[] args) {
        readBufferMap = new HashMap<>();
        try {
            AsynchronousServerSocketChannel ssc = AsynchronousServerSocketChannel.open();
            ssc.bind(CONS.inetSocketAddress);
            ssc.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
                @Override
                public void completed(AsynchronousSocketChannel sc, Object attachment) {
                    System.out.println(Thread.currentThread().getName());
                    System.out.println(System.currentTimeMillis());
                    if (sc != null) {
                        try {
                            System.out.println("accept future get a connection " + sc.getRemoteAddress());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        handleSC(sc);
                    }
                }

                @Override
                public void failed(Throwable exc, Object attachment) {

                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
    }

    private static void handleSC(AsynchronousSocketChannel sc) {
        ByteBuffer buffer = ByteBuffer.allocate(5);
        readBufferMap.put(sc, buffer);
        //这里的Read和NIO的read有什么不同呢？通过把buffer改大改小来测试
        //NIO的read，buffer改大改小，都是只把目前可得到的数据（如何定义目前可得到？答就是目前可得到）读入, 其中执行了从内核到用户的数据读的过程。
        //AIOFuture的read，直接返回future,其中不执行操作. future的get的时候, 也只是在没有数据的时候等而已.
        Future<Integer> readFuture = sc.read(buffer);
        int readNum = 0;
        try {
            StringBuilder stringBuilder = new StringBuilder();
            while (stringBuilder.lastIndexOf(CONS.PROTOCOL_TAIL) == -1 && readNum != -1) {
                try {
                    readNum = readFuture.get(2, TimeUnit.SECONDS);//阻塞2s
                    System.out.println("= receite: " + readNum + "bytes");
                    int curPos = buffer.position();
                    System.out.println("= " + curPos + " current position");
                    buffer.flip();
                    byte[] dst = new byte[curPos];
                    buffer.get(dst);
                    String strRece = new String(dst, CONS.CHARSET_NAME);
                    System.out.println("= receive: " + strRece);
                    stringBuilder.append(strRece);
                    buffer.clear();
                    Thread.sleep(1 * 1000);
                    readFuture = sc.read(buffer); // 这里
//                    readNum = channelToTreat.read(buffer);
                } catch (TimeoutException e) {
                    System.out.println("read Future time out, return after 5s");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("+ " + readNum + " bytes read");
            System.out.println("+ end treat " + stringBuilder.toString());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }


}